package de.hohenheim.view.mobile.animation;

import java.util.Observable;
import de.hohenheim.view.map.RoomMap;
import de.hohenheim.view.mobile.ForkTruckFigure;
import de.hohenheim.view.mobile.animation.listeners.AnimationFinishedEvent;
import de.hohenheim.view.mobile.animation.listeners.AnimationStartedEvent;
/**
 * This class animates the loding of a fork truck. During the aniation a
 * rectangle is drawn onto the fork which gets bigger over time when unload=false
 * and smaller otherwise. It shall simulate that packeges are loaded onto the fork or 
 * unloaded from the fork.
 * @author Marc Fernandes
 *
 */
public class LoadingAnimator extends Observable implements Runnable, Animator {
	/**
	 * The {@link RoomMap} where the animation takes place. 
	 */
	RoomMap map;
	/**
	 * The fork truck which is loaded/unloaded
	 */
	ForkTruckFigure animationFigure;
	/**
	 * Indicates if the animation is finished.
	 */
	boolean finished     = false;
	/**
	 * indicates if the animation is stopped.
	 */
	boolean stopped      = false;
	/**
	 * The time needed for loading/unloading
	 */
	long loading_time;
	/**
	 * The height of the rectangle which should be drawn in px when it is fully loaded.
	 */
	int max_load;
	/**
	 * A variable to calcualate the number of loading steps depending on the loading_time.
	 */
	int loading_pieces;
	/**
	 * A marker to determine, when loading is finished.
	 */
	int time_left;
	/**
	 * A variable to set if we want to load the fork truck or to unload it.
	 */
	boolean unload=false;
	/**
	 * Constructor.
	 * @param {@link RoomMap} map - the RoomMap where animation takes place. 
	 * @param {@link ForkTruckFigure} figure - The fork truck which we load / unload.  
	 * @param int loading_time - The time we need for loading/unloading.
	 * @param boolean unload - True if we want to unload the fork truck, false if we want to load it
	 */
	public LoadingAnimator(RoomMap map, ForkTruckFigure figure, int loading_time, boolean unload) {
		this.animationFigure = figure;
		this.map             = map;
		this.loading_time    = loading_time;
		this.max_load        = animationFigure.getMaxLoad();
		//We take 1 second for every change in loading
		if(unload) {
			this.loading_pieces=max_load;	
		} else {
		  this.loading_pieces  = this.max_load/(loading_time/500);
		}
		this.time_left       = loading_time; 
		this.unload=unload;
	}
	
	public boolean isFinished() {
		return this.finished;
	}
	/**
	 * Runs the animation by recursion. If the animation is finished it notifies the observers listening for 
	 * a finishing event.  
	 */
	public void run() {
		if (this.stopped) {
			return;
		}
		if(this.time_left<0) {
			this.finished=true;
			int animationtype=AnimationFinishedEvent.LOADING_FINISHED;
			if(this.unload) {
				animationtype=AnimationFinishedEvent.UNLOADING_FINISHED;
				this.animationFigure.setActualLoad(0);
			} else {
			  this.animationFigure.setActualLoad(this.max_load);
			}
			//notify Listeners
			animationFigure.notifyAnimationListener(new AnimationFinishedEvent(animationFigure, animationtype));
			//notify observers
			setChanged();
			notifyObservers(this.animationFigure);
			return;
		}
		this.time_left-=500;
		this.animationFigure.setActualLoad(this.loading_pieces);
		if(unload) {
			this.loading_pieces-=this.max_load/(loading_time/500);	
		} else {
		  this.loading_pieces+=this.max_load/(loading_time/500);
		}
		map.getDisplay().timerExec(500, this);			
	}
	
	/**
	 * Starts the animation. To start the animation only use this method. do not use run()!
	 */
	public void start() {
		//notify Listeners
		if(this.unload) {
		  animationFigure.notifyAnimationListener(new AnimationStartedEvent(animationFigure, AnimationStartedEvent.UNLOADING_STARTED));
		} else {
			//notify Listeners
			animationFigure.notifyAnimationListener(new AnimationStartedEvent(animationFigure, AnimationStartedEvent.LOADING_STARTED));
		}
		this.stopped=false;
		map.getDisplay().timerExec(0, this);
	}
	
	/**
	 * Stops the animation.
	 */
	public void stop() {
		this.stopped=true;		
		
	}
	
	/**
	 * Returns true if the animation is stopped.
	 */
	public boolean isStopped() {
		return this.stopped;		
		
	}
}

